package com.easymin.weixin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easymin.weixin.mapper.WxBindMapper;
import com.easymin.weixin.service.WxUserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhyu
 * @date 2019-08-04 07:47:42
 * 后面可以对过期时间进行优化,主要还要减除一个估计时间, 微信服务器生成并传递 信息给我,我们用tocken访问微信服务器到过期减除通过前;
 * 代码结构优化, 下次提取出和微信通信的restTemplate方式,
 */
@Service
public class WxUserInfoServiceImpl implements WxUserInfoService {

    @Value("${weixin.appId}")
    private String appId;

    @Value("${weixin.secret}")
    private String secret;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private WxBindMapper wxBindMapper;

    public static final String GRANT_TYPE = "client_credential";

    public static final String GRANT_TYPE_NAME = "grant_type";

    public static final String APPID_NAME = "appid";

    public static final String SECRET_NAME = "secret";

    public static final String ACCESS_TOKEN_NAME = "access_token";

    public static final String EXPIRES_IN_NAME = "expires_in";

    public static final String OPENID_NAME = "openid";

    public static final String NICKNAME_NAME = "nickname";

    public static final String HEAD_IMG_URL_NAME = "headimgurl";

    public static final String PHONE_NAME = "phone";


    public static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type={grant_type}&appid={appid}&secret={secret}";

    public static final String INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={access_token}&openid={openid}&lang=zh_CN";

    public static final String ERROR_CODE_NAME = "errcode";

    private Tocken tocken;

    @Override
    public Map<String, String> getWeixinUserInfo(String openId) {
        try {
            String token = getToken();
            return getWeixinUserInfo(token, openId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public Map<String, String> getWeixinUserInfoByPhone(String phone){
        Map<String, String> map = new HashMap<>();
        if (null != phone && 0 != phone.trim().length()) {
            String openId = wxBindMapper.findOpenIdByPhone(phone);
            map.put(OPENID_NAME, openId);
            Map<String, String> weixinUserInfo = getWeixinUserInfo(openId);
            if (null != weixinUserInfo)
                map.putAll(weixinUserInfo);
        }
        return map;
    }

    @Override
    public Map<String, Map<String, String>> getWeixinUserInfoByPhone(String[] phones) {
        Map<String, Map<String, String>> maps = new HashMap<>();
        if (null != phones && 0 != phones.length) {
            for (int i = 0; i < phones.length; i++) {
                String phone = phones[i];
                if (null != phone && 0 != phone.trim().length()) {
                    String openId = wxBindMapper.findOpenIdByPhone(phone);
                    Map<String, String> map = new HashMap<>();
                    map.put(OPENID_NAME, openId);
                    maps.put(phone, map);
                }
            }
        }
        for (Map<String, String> map : maps.values()) {
            String openId = map.get(OPENID_NAME);
            Map<String, String> weixinUserInfo = getWeixinUserInfo(openId);
            if (null != weixinUserInfo)
                map.putAll(weixinUserInfo);
        }
        return maps;
    }


    public Map<String, String> getWeixinUserInfo(String access_tocken, String openId) throws UnsupportedEncodingException {
        if (null == access_tocken)
            return null;
        Map<String, String> kv = new HashMap<>();
        kv.put(ACCESS_TOKEN_NAME, access_tocken);
        kv.put(OPENID_NAME, openId);
        String jsonStr = restTemplate.getForObject(INFO_URL, String.class, kv);
        JSONObject obj = JSON.parseObject(jsonStr);
        if (null != obj && null == obj.get(ERROR_CODE_NAME)) {
            String headImgUrl = obj.getString(HEAD_IMG_URL_NAME);
            String nickName = obj.getString(NICKNAME_NAME);
            Map<String, String> map = new HashMap<>();
            map.put(HEAD_IMG_URL_NAME, headImgUrl);
            map.put(NICKNAME_NAME, new String(nickName.getBytes("ISO-8859-1"), "utf-8"));
            return map;
        }
        return null;
    }

    public String getToken() {
        if (null == tocken || System.currentTimeMillis() < tocken.getDeadTime()) {
            return getTockenFromWeixin().getAccess_token();
        } else {

        }
        return null;
    }

    /***
     * 获取Tocken 第一步
     * @return
     */
    public Tocken getTockenFromWeixin() {
        Map<String, String> kv = new HashMap<>();
        kv.put(GRANT_TYPE_NAME, GRANT_TYPE);
        kv.put(APPID_NAME, appId);
        kv.put(SECRET_NAME, secret);
        String jsonStr = restTemplate.getForObject(TOKEN_URL, String.class, kv);
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        if (null != jsonObject && null == jsonObject.get("ERROR_CODE_NAME")) {
            String accessTocken = jsonObject.getString(ACCESS_TOKEN_NAME);
            long expires_in = jsonObject.getLongValue(EXPIRES_IN_NAME);
            if (null != accessTocken) {
                return new Tocken(accessTocken, expires_in);
            }
        }
        return null;
    }


    class Tocken {

        private String access_token;
        private long expires_in;
        private long deadTime;

        public Tocken(String access_token, long expires_in) {
            this.access_token = access_token;
            this.expires_in = expires_in;
        }

        public String getAccess_token() {
            return access_token;
        }

        public void setAccess_token(String access_token) {
            this.access_token = access_token;
        }

        public long getExpires_in() {
            return expires_in;
        }

        public void setExpires_in(long expires_in) {
            this.expires_in = expires_in;
        }

        public long getDeadTime() {
            return deadTime;
        }

        public void setDeadTime(long deadTime) {
            this.deadTime = deadTime;
        }
    }

}
